package it.univaq.mancoosi.injectors.systemconfiguration.managers;

import java.io.*;
import java.util.*;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.util.EcoreUtil;


import it.univaq.mancoosi.injectors.systemconfiguration.managers.ubuntu.UbuntuConfigurationManager;
import it.univaq.mancoosi.injectors.systemconfiguration.managers.ubuntu.UbuntuEnvironmentManager;
import it.univaq.mancoosi.mancoosimm.Configuration;
import it.univaq.mancoosi.mancoosimm.Conflict;
import it.univaq.mancoosi.mancoosimm.Dependence;
import it.univaq.mancoosi.mancoosimm.File;
import it.univaq.mancoosi.mancoosimm.InstalledPackage;
import it.univaq.mancoosi.mancoosimm.MancoosiFactory;
import it.univaq.mancoosi.mancoosimm.ModuleCache;
import it.univaq.mancoosi.mancoosimm.NotInstalledPackage;
import it.univaq.mancoosi.mancoosimm.PackageSetting;
import it.univaq.mancoosi.mancoosimm.Service;


public abstract class PackageManager {

	protected static  PackageManager INSTANCE ;

	protected Configuration configuration;
	protected HashMap<String, InstalledPackage> pkgMap; 
	protected HashMap<String, InstalledPackage> pkgFromSyncMap; 
	protected HashMap<InstalledPackage, ArrayList<File>> pkgSettingsMap;
	protected HashMap<String, String> versionTypeMap;
	protected FileSystemManager fileSystemManager;
	protected MancoosiFactory factory;
	protected ArrayList<InstalledPackage> instPkgToBeDeleted;
	protected ArrayList<NotInstalledPackage> notInstPkgToBeDeleted;

	protected PackageManager(){
		this.configuration = ConfigurationManager.getInstance().getConfiguration();
		this.pkgMap = new HashMap<String, InstalledPackage>();
		this.pkgFromSyncMap = new HashMap<String, InstalledPackage>();
		this.pkgSettingsMap = new HashMap<InstalledPackage, ArrayList<File>>();
		this.fileSystemManager = FileSystemManager.getInstance();
		this.factory = MancoosiFactory.eINSTANCE; 
		instPkgToBeDeleted = new ArrayList<InstalledPackage>();
		notInstPkgToBeDeleted = new ArrayList<NotInstalledPackage>();

		this.versionTypeMap =  new HashMap<String, String>();
		versionTypeMap.put("=", "eq");
		versionTypeMap.put(">=", "ge");
		versionTypeMap.put(">", "gt");
		versionTypeMap.put(">>", "ggt");
		versionTypeMap.put("<", "lt");
		versionTypeMap.put("<=", "le");
		versionTypeMap.put("<<", "llt");
	}

	/*	public void registerResource(Resource resource) {
		this.resource = resource;		
	}
	 */		
	public static PackageManager getInstance() {
		return INSTANCE;
	}



	/* This method works but actually is never used.
	private void processPackageFiles(BufferedReader pkgFiles, InstalledPackage pkg) {

		Scanner scanner = new Scanner(pkgFiles);
		String filePath, rights;
		File file;

	    try {
	      //first use a Scanner to get each line
	      while ( scanner.hasNextLine() ){

	    	  filePath = scanner.nextLine();   	  
	    	  String[] cmd = {"/bin/sh","-c"," ls -l \"" + filePath + "\" | awk '{print $1}'"};
	    	  Process p = Runtime.getRuntime().exec(cmd);
	    	  BufferedReader input =
	    		  new BufferedReader
	    		  (new InputStreamReader(p.getInputStream()));

	    	  rights = input.readLine();			
	    	  p.destroy();
	    	  input.close();

	      }
	    } catch (Exception err) {
	    	err.printStackTrace();
	    }

	}
	 */

	protected abstract void processPackageMetadata(BufferedReader packageInfo, InstalledPackage installedPackage) throws IOException;



	public InstalledPackage createPackage(String packageName) {

		InstalledPackage pkg = factory.createInstalledPackage();
		pkg.setName(packageName);
		System.out.println("Creating new package " + packageName);
		configuration.getInstalledPackages().add(pkg);
		pkgMap.put(pkg.getName(), pkg);

		return pkg;	
	}


	//mirco
	public void removePackage(InstalledPackage packageToBeRemoved) {

//		EList<Service> servicesList = packageToBeRemoved.getServices();
//		int k = servicesList.size();
//		for (int j=0; j < servicesList.size(); j++) {
//			if(UbuntuEnvironmentManager.getInstance().getEnvironment().getRunningServices() != null){			
//				int indexRs = UbuntuEnvironmentManager.getInstance().getEnvironment().getRunningServices().indexOf(servicesList.get(j));
//				UbuntuEnvironmentManager.getInstance().getEnvironment().getRunningServices().remove(indexRs);
//			}
//
//		}

		PackageSetting pkgSetting = packageToBeRemoved.getPackageSettings();

		if (pkgSetting != null) {

			EcoreUtil.delete(pkgSetting);
		}

	}

	public Boolean existsPackage(String packageName) {
		
		return this.pkgMap.containsKey(packageName);

//		EList<InstalledPackage> installedPackages = ConfigurationManager.getInstance().getConfiguration().getInstalledPackages();
//
//		Iterator<InstalledPackage> installedPackagesIterator = installedPackages.iterator();
//		InstalledPackage installedPackageElement = null;
//		Boolean found = false;
//
//		while ( installedPackagesIterator.hasNext() && !found ) {
//			installedPackageElement = installedPackagesIterator.next();
//			if ( installedPackageElement.getName().equals(packageName) ) {
//				found = true;
//				pkgMap.put(packageName,installedPackageElement);
//			}
//		}
//
//		return found;
	}


	public List<File> getConfFiles(InstalledPackage installedPackage) {

		return pkgSettingsMap.get(installedPackage);

	}

	public InstalledPackage getInstalledPackageByName (String packageName) {
		
		return pkgMap.get(packageName);
		/*
		Iterator<InstalledPackage> iterator = configuration.getInstalledPackages().iterator();
		while (iterator.hasNext()) {
			InstalledPackage curr = iterator.next();
			if (curr.getName().equals(packageName))
				return curr;
		}
		return null;
		*/ 
	}
	
	public void syncMap () {
		Iterator<InstalledPackage> iterator  = null;
		if(UbuntuConfigurationManager.getInstance().getConfiguration() != null){
			iterator = UbuntuConfigurationManager.getInstance().getConfiguration().getInstalledPackages().iterator();
		}
		if(iterator != null){
			while (iterator.hasNext()) {
				InstalledPackage curr = iterator.next();
				this.pkgMap.put(curr.getName(), curr);
			}
		}
	}

	protected abstract void createSingleDeps(String[] singleDeps, Dependence owner);

	protected abstract void createSingleConflicts(String[] singleConflicts, Conflict owner);

	protected abstract void processPackageMetadataLine(String aLine, InstalledPackage pkg);

	protected abstract void processConfFiles(List<String> conffilesBlock, InstalledPackage installedPackage);

	protected abstract void createDocFiles(InstalledPackage installedPackage)  throws IOException;

	public abstract void setFeaturesOfInstalledPackages(HashMap<String, InstalledPackage> pkgMap) throws IOException;

	public abstract void createPackageElementsFromSystem() throws IOException;

	public abstract void synchronize() throws IOException;

	public HashMap<String, InstalledPackage> getPkgMap() {
		return pkgMap;
	}

}